/*
 * JoinComponentDefinition.java
 *
 * Created on September 27, 2006, 11:37 PM
 *
 * (C) 2006 R. Alexander Milowski
 */

package com.smallx.xproc.library;

import com.smallx.xpath.XPathMatcherFactory;
import com.smallx.xproc.ComponentType;
import java.net.URI;
import java.util.Collection;
import java.util.logging.Level;
import org.infoset.component.Component;
import org.infoset.component.ComponentBase;
import org.infoset.component.ComponentDefinition;
import org.infoset.xml.Document;
import org.infoset.xml.Item;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;
import org.infoset.xml.util.DocumentSource;

/**
 *
 * @author alex
 */
public class ViewportEndComponentDefinition implements ComponentDefinition {

   static ComponentType defaultType = new ComponentType(LibraryComponents.VIEWPORT_START_TYPE);
   public static Name MATCHES_PORT = Name.create("matches");
   public static Name NON_MATCHES_PORT = Name.create("non-matches");
   public static Name OUTPUT_PORT = Name.create("input");
   static {
      defaultType.addInputPort(MATCHES_PORT,true);
      defaultType.addInputPort(NON_MATCHES_PORT,false);
      defaultType.addOutputPort(OUTPUT_PORT,false);
   }
   
   class End extends ComponentBase {
      
      ItemDestination output = null;
      
      End() {
         super(type.getName());
      }
      
      public void bindResource(Name port, URI location) throws XMLException {
         throw new XMLException("Binding resources to matches or non-matches is not allowed for end viewports.");
      }

      public void bindResource(Name port, Document doc) throws XMLException {
         throw new XMLException("Binding resources to matches or non-matches is not allowed for end viewports.");
      }
   
      public void bindOutputPort(Name port, ItemDestination output) throws XMLException {
         this.output = output;
      }
   
      public ItemDestination getInputPort(Name port) 
         throws XMLException
      {
         if (port.equals(NON_MATCHES_PORT)) {
            return new ItemDestination() {
               public void send(Item item) 
                  throws XMLException
               {
                  if (output!=null) {
                     output.send(item);
                  }
               }
            };
         } else {
            return new ItemDestination() {
               boolean isFineLog = context.getLog().isLoggable(Level.FINE);
               public void send(Item item) 
                  throws XMLException
               {
                  Item.ItemType type = item.getType();
                  if (output!=null && type!=Item.ItemType.DocumentEndItem && type!=Item.ItemType.DocumentItem) {
                     if (isFineLog) {
                        context.getLog().fine("Sending: "+item);
                     }
                     output.send(item);
                  }
               }
            };
            
         }
      }

      public void onDocumentInput(Name port, Document doc) 
         throws XMLException 
      {
         if (!port.equals(NON_MATCHES_PORT)) {
            if (output!=null) {
               DocumentSource.generate(doc,false,output);
            }
         } else {
            throw new XMLException("Document input isn't possible for end viewports.");
         }
      }
   
   }
   protected ComponentType type;
   protected XPathMatcherFactory expression;
   
   public ViewportEndComponentDefinition() {
      this(defaultType);
   }
   /** Creates a new instance of FlowComponentDefinition */
   public ViewportEndComponentDefinition(ComponentType type) {
      this.type = type;
   }
   
   public void setExpression(XPathMatcherFactory exp) {
      this.expression = exp;
   }
   
   public Component newInstance()
      throws XMLException 
   {
      return new End();
   }
      
   public Name getName() {
      return type.getName();
   }

   public String getVersion() {
      return null;
   }

   public String getVendor() {
      return null;
   }

   public URI getVendorLocation() {
      return null;
   }

   public Collection<Name> getInputs() {
      return type.getInputPortNames();
   }

   public Collection<Name> getOutputs() {
      return type.getOutputPortNames();
   }

}

